package com.ctshk.rpc.train.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.CurrencyIdCode;
import com.ctshk.common.constant.ElasticSearchConstant;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.elasticsearch.config.ElasticSearchConfiguration;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.bus.BusRecommendationStatusCode;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.service.support.BaseService;
import com.ctshk.common.utils.Assist;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.rpc.cms.dto.NoticeDTO;
import com.ctshk.rpc.cms.req.BannerPositionByTypeReq;
import com.ctshk.rpc.cms.service.INoticeService;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.MainDataStationDTO;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.system.service.IMainDataManualSystemService;
import com.ctshk.rpc.system.service.IMainDataStationService;
import com.ctshk.rpc.train.dto.ApiTrainProductDTO;
import com.ctshk.rpc.train.dto.ApiTrainProductSeatInfoDTO;
import com.ctshk.rpc.train.dto.Constants;
import com.ctshk.rpc.train.dto.TrainNoticeDTO;
import com.ctshk.rpc.train.dto.es.MainDataStationCacheDTO;
import com.ctshk.rpc.train.dto.es.TrainNumberCacheDTO;
import com.ctshk.rpc.train.dto.es.TrainNumberSeatLevelCacheDTO;
import com.ctshk.rpc.train.dto.es.TrainProductCacheDTO;
import com.ctshk.rpc.train.dto.h5.*;
import com.ctshk.rpc.train.dto.pc.TrainProductDetailPcDTO;
import com.ctshk.rpc.train.entity.TrainProduct;
import com.ctshk.rpc.train.entity.TrainProductReservationSettings;
import com.ctshk.rpc.train.entity.es.MainDataStationCache;
import com.ctshk.rpc.train.entity.es.TrainNumberCache;
import com.ctshk.rpc.train.enums.MtrTrainNumber;
import com.ctshk.rpc.train.enums.SeatAliApiEnum;
import com.ctshk.rpc.train.mapper.*;
import com.ctshk.rpc.train.req.*;
import com.ctshk.rpc.train.service.ITrainApiService;
import com.ctshk.rpc.train.service.ITrainNumberService;
import com.ctshk.rpc.train.service.ITrainProductAppAndPcService;
import com.ctshk.rpc.train.service.ITrainProductService;
import com.github.houbb.opencc4j.util.ZhConverterUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 火车产品表 服务实现类
 * </p>
 *
 * @author 彭柳霖
 * @since 2021-03-11
 */
@Slf4j
@DubboService
public class TrainProductAppAndPcServiceImpl extends ServiceImpl<TrainProductMapper, TrainProduct> implements ITrainProductAppAndPcService, BaseService {

    @DubboReference
    ITrainProductService trainProductService;

    @DubboReference
    ITrainNumberService trainNumberService;

    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Autowired
    TrainElasticSearchMapper trainElasticSearchMapper;

    @Autowired
    private TrainStationElasticSearchMapper stationElasticSearchMapper;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    private TrainStationCodeMapper stationCodeMapper;

    @DubboReference
    private ITrainApiService iTrainApiService;

    @DubboReference
    IMainDataStationService mainDataStationService;

    @DubboReference
    private INoticeService noticeService;

    @Autowired
    TrainProductReservationSettingsMapper reservationSettingsMapper;
    /**
     * 汇率服务
     */
    @DubboReference
    private IMainDataCurrencyService mainDataCurrencyService;

    @Override
    public Result trainCacheInit() {
//        // 清除旧数据
//        trainElasticSearchMapper.deleteAll();

        // 构建上架数据
        List<TrainNumberCacheDTO> trainNumberCacheDTOS = buildData(null, null);

        // 上架
        up(trainNumberCacheDTOS, RedisConstants.TRAIN_UPDATE_TIME);
        return Result.success();
    }

    private void up(List<TrainNumberCacheDTO> trainNumberCacheDTOS, String UpdateTimeKey) {
        // 保存检索信息到es
        List<TrainNumberCacheDTO> saveList = trainNumberCacheDTOS.stream().filter(item -> item.getTrainProductCacheDTOS() != null && item.getTrainProductCacheDTOS().size() > 0).collect(Collectors.toList());
        List<TrainNumberCache> trainNumberCaches = EntityUtil.copyList(saveList, TrainNumberCache.class);
        trainElasticSearchMapper.saveAll(trainNumberCaches);
        // 标记 上架/更新 时间
        setCacheUpdate(UpdateTimeKey);
        // 保存可售票数到redis
        saveList.forEach(item -> {
            item.getTrainProductCacheDTOS().forEach(Product -> {
                Integer inventory = Product.getInventory();
                if (inventory == null) {
                    return;
                }
                redisTemplate.opsForValue().set(RedisConstants.BUS_REMAINDER_NUMBER + Product.getId(), inventory.toString());
            });
        });
    }

    /**
     * 设置缓存更新时间
     *
     * @param key
     */
    private void setCacheUpdate(String key) {
        redisTemplate.opsForValue().set(key, JSON.toJSONString(LocalDateTime.now()));
    }

    /**
     * 获取缓存更新时间
     *
     * @param index
     * @return
     */
    private LocalDateTime getCacheUpdate(String index) {
        return JSON.parseObject(redisTemplate.opsForValue().get(index), LocalDateTime.class);
    }


    private List<TrainNumberCacheDTO> buildData(List<Long> ids, LocalDateTime now) {
        // 查询火车车次
        List<TrainNumberCacheDTO> trainNumberCacheDTOS = trainNumberService.findTrainNumberList(ids, now);
        List<String> trainNumberNames = trainNumberCacheDTOS.stream().map(TrainNumberCacheDTO::getTrainNumberName).collect(Collectors.toList());

        // 查询火车产品
        List<TrainProductCacheDTO> busProductDTOS = trainProductService.queryTrainProductList(trainNumberNames);

        // 将产品设置进路线
        Assist.forEach(trainNumberCacheDTOS, numberCacheDTO -> numberCacheDTO.setTrainProductCacheDTOS(busProductDTOS.stream().filter(item -> item.getTrainNumberName().equals(numberCacheDTO.getTrainNumberName())).collect(Collectors.toList())));

        // 过滤没有产品的车次
        List<TrainNumberCacheDTO> newTrainNumberCacheDTOs = new ArrayList<>();
        for (TrainNumberCacheDTO numberCacheDTO : trainNumberCacheDTOS) {
            if (Assist.isEmpty(numberCacheDTO.getTrainProductCacheDTOS())) {
                continue;
            }
            newTrainNumberCacheDTOs.add(numberCacheDTO);
        }

        return newTrainNumberCacheDTOs;
    }

    @Override
    public Result trainCacheUpdateByTime() {
        up(buildData(null, getCacheUpdate(RedisConstants.TRAIN_UPDATE_TIME)), RedisConstants.TRAIN_UPDATE_TIME);
        return Result.success();
    }

    @Override
    public Result trainCacheUpdateById(List<Long> ids) {
        up(buildData(ids, null), RedisConstants.TRAIN_UPDATE_TIME);
        return Result.success();
    }

    @Override
    public Result remainderNumberUpdate(CacheSetReq req) {
        String key = RedisConstants.TRAIN_REMAINDER_NUMBER + req.getKey();
        Boolean hasKey = redisTemplate.hasKey(key);
        // 如果key不存在
        if (!hasKey) {
            return Result.failed(SystemError.BUS_PRODUCT_9035);
        }
        // 绑定操作key
        BoundValueOperations<String, String> valueOps = redisTemplate.boundValueOps(key);
        Integer type = req.getType();
        String msg = "操作成功";
        RLock lock = redissonClient.getLock(RedisConstants.TRAIN_REMAINDER_NUMBER_LOCK + req.getKey());
        try {
            lock.lock(30, TimeUnit.SECONDS);
            int num = Integer.valueOf(valueOps.get()).intValue();
            // 根据操作类型执行操作
            if (num != -1 && type.intValue() == RedisOpsStatusCode.ADD.getCode().intValue()) {
                Long increment = valueOps.increment(req.getVal());
                msg += " 剩余票数为：" + increment;
            } else if (num != -1 && type.intValue() == RedisOpsStatusCode.MIN.getCode().intValue()) {
                if (num - req.getVal() >= 0) {
                    Long decrement = valueOps.decrement(req.getVal());
                    msg += " 剩余票数为：" + decrement;
                } else {
                    return Result.failed(SystemError.BUS_PRODUCT_9036);
                }
            } else if (type.equals(RedisOpsStatusCode.SET.getCode())) {
                valueOps.set(req.getVal().toString());
            } else if (type.equals(RedisOpsStatusCode.DEL.getCode())) {
                Map<String, Boolean> resultMap = deletString(Arrays.asList(key));
                Set<String> keySet = resultMap.keySet();
                Iterator<String> iterator = keySet.iterator();
                Boolean result = resultMap.get(iterator.next());
                if (!result) {
                    msg = "操作失败";
                }
            }
        } finally {
            lock.unlock();
        }
        return Result.success(msg);
    }

    @Override
    public Result<HomeTrainH5DTO> hotLineQuery() {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        boolQuery.must(QueryBuilders.matchQuery("trainProductCacheDTOS.recommendationStatus", BusRecommendationStatusCode.RECOMMENDATION.getCode()));
        sourceBuilder.query(boolQuery);
        sourceBuilder.sort(new FieldSortBuilder("trainProductCacheDTOS.saleCount").order(SortOrder.DESC));
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_INDEX).source(sourceBuilder);

        List<TrainProductCacheDTO> trainProductList = new ArrayList<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<TrainNumberCacheDTO> trainNumberCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                TrainNumberCacheDTO trainNumberCacheDTO = JSON.parseObject(sourceAsString, TrainNumberCacheDTO.class);
                trainNumberCacheDTOS.add(trainNumberCacheDTO);
            }
            if (trainNumberCacheDTOS.size() > 0) {
                trainNumberCacheDTOS.forEach(number -> {
                    trainProductList.addAll(number.getTrainProductCacheDTOS().stream().filter(item -> item.getRecommendationStatus().equals(BusRecommendationStatusCode.RECOMMENDATION.getCode())).collect(Collectors.toList()));
                });
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }
        Map<String, TrainProductCacheDTO> maps = trainProductList.stream().collect(Collectors.toMap(TrainProductCacheDTO::getProductCode, Function.identity(), (key1, key2) -> key2));
        List<RecommendedTrainH5DTO> trainH5DTOS = EntityUtil.copyList(trainProductList, RecommendedTrainH5DTO.class);
        for (RecommendedTrainH5DTO trainH5DTO : trainH5DTOS) {
            trainH5DTO.setDepartureDate(LocalDate.now());
            trainH5DTO.setWeek(getWeek());
            trainH5DTO.setPrice(maps.get(trainH5DTO.getProductCode()).getTrainNumberSeatLevelCacheDTOS().get(0).getH5ChildPrice());
        }
        HomeTrainH5DTO homeTrainH5DTO = new HomeTrainH5DTO();
        homeTrainH5DTO.setRecommendedTrainH5DTOS(trainH5DTOS);

        //获取通告信息
        BannerPositionByTypeReq cmsReq = new BannerPositionByTypeReq().setLinkType(4).setCode("TRAIN_NOTICE");
        List<NoticeDTO> tripNotice = noticeService.queryListByCode(cmsReq);
        List<TrainNoticeDTO> trainNoticeDTOS = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(tripNotice)) {
            for (NoticeDTO notice : tripNotice) {
                TrainNoticeDTO tourNoticeDTO = new TrainNoticeDTO();
                tourNoticeDTO.setTitle(notice.getTitle());
                tourNoticeDTO.setContent(notice.getNoticeContent());
                trainNoticeDTOS.add(tourNoticeDTO);
            }
        }
        homeTrainH5DTO.setMessage(trainNoticeDTOS);

        //homeTrainH5DTO.setNoticeName("香港中旅社取消由即日起至1月31日期間所有前往...");

        return Result.success(homeTrainH5DTO);
    }

    private String getWeek() {
        final String[] dayNames = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek < 0) {
            dayOfWeek = 0;
        }
        return dayNames[dayOfWeek];
    }

    @Override
    public Result<List<TrainProductH5DTO>> reservationQuery(TrainAppQueryReq req) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (req == null) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14002);
        }

        // 上车站
        if (req.getBoardingStationName() != null) {
            boolQuery.filter(QueryBuilders.matchPhraseQuery("trainProductCacheDTOS.boardingStationName", req.getBoardingStationName()));
        }

        // 下车站
        if (req.getAlightingStationName() != null) {
            boolQuery.filter(QueryBuilders.matchPhraseQuery("trainProductCacheDTOS.alightingStationName", req.getAlightingStationName()));
        }

        // 出发时间
        if (req.getDepartureDate() != null) {
            RangeQueryBuilder startQueryBuilder = QueryBuilders.rangeQuery("trainProductCacheDTOS.channelSaleCacheList.dateBegin");
            RangeQueryBuilder endQueryBuilder = QueryBuilders.rangeQuery("trainProductCacheDTOS.channelSaleCacheList.dateEnd");
            startQueryBuilder.lte(req.getDepartureDate());
            endQueryBuilder.gte(req.getDepartureDate());
            boolQuery.must(startQueryBuilder);
            boolQuery.must(endQueryBuilder);
        }
        sourceBuilder.query(boolQuery);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_INDEX).source(sourceBuilder);
        List<TrainProductCacheDTO> trainProductList = new ArrayList<>();
        Map<String, TrainNumberCacheDTO> trainNumberCacheDTOMap = new HashMap<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<TrainNumberCacheDTO> trainNumberCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                TrainNumberCacheDTO busLineCacheDTO = JSON.parseObject(sourceAsString, TrainNumberCacheDTO.class);
                trainNumberCacheDTOS.add(busLineCacheDTO);
            }
            if (trainNumberCacheDTOS.size() > 0) {
                trainNumberCacheDTOMap = trainNumberCacheDTOS.stream().collect(Collectors.toMap(TrainNumberCacheDTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
                trainNumberCacheDTOS.forEach(line -> {
                    trainProductList.addAll(line.getTrainProductCacheDTOS());
                });
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }
        Map<String, TrainProductCacheDTO> maps = trainProductList.stream().collect(Collectors.toMap(TrainProductCacheDTO::getProductCode, Function.identity(), (key1, key2) -> key2));
        List<TrainProductH5DTO> trainProductH5DTOS = EntityUtil.copyList(trainProductList, TrainProductH5DTO.class);

        // 获取阿里云api产品信息
        trainProductH5DTOS = buildAliTrainList(req, trainProductH5DTOS);

        List<TrainProductH5DTO> newTrainProductH5DTO = new ArrayList<>();
        for (TrainProductH5DTO trainH5DTO : trainProductH5DTOS) {
            if (trainH5DTO.getProductSource() == null || !trainH5DTO.getProductSource().equals(Constants.ALI)) {
                // 获取最低价格
                BigDecimal price = maps.get(trainH5DTO.getProductCode()).getTrainNumberSeatLevelCacheDTOS().stream().map(TrainNumberSeatLevelCacheDTO::getH5Price).min(BigDecimal::compareTo).get();
                trainH5DTO.setPrice(price);
                trainH5DTO.setRunningTime(convertRunningTime(trainH5DTO.getDepartureTime(), trainH5DTO.getTerminusTime()));
                trainH5DTO.setTrainStopStationCacheDTOS(trainNumberCacheDTOMap.get(trainH5DTO.getTrainNumberName()).getTrainStopStationCacheDTOS());
            }
            if (trainH5DTO.getAlightingStationName().equals(req.getAlightingStationName()) && trainH5DTO.getBoardingStationName().equals(req.getBoardingStationName())) {
                // 是否为高速列车筛选
                if (req.getIsExpressTrain() == 1) {
                    if (trainH5DTO.getTrainNumberName().startsWith("D") || trainH5DTO.getTrainNumberName().startsWith("G")
                            || trainH5DTO.getTrainNumberName().startsWith("C")) {
                        newTrainProductH5DTO.add(trainH5DTO);
                    }
                } else {
                    newTrainProductH5DTO.add(trainH5DTO);
                }
            }
        }
        return Result.success(newTrainProductH5DTO);
    }

    /**
     * @param d1 出发时间
     * @param d2 到达时间
     * @return
     */
    private String convertRunningTime(LocalDateTime d1, LocalDateTime d2) {
        if (d1 == null || d2 == null) {
            return null;
        }
        long minutes = Duration.between(d1, d2).toMinutes();
        long minute = minutes % 60L;
        long hour = minutes / 60L;
        return hour + "小时" + minute + "分";
    }

    private List<TrainProductH5DTO> buildAliTrainList(TrainAppQueryReq req, List<TrainProductH5DTO> oldTrainProductH5DTOS) {
        oldTrainProductH5DTOS = oldTrainProductH5DTOS.stream().filter(seatH5DTO -> {
            // 过滤不符合的出发站,到达站
            return seatH5DTO.getBoardingStationName().equals(req.getBoardingStationName())
                    && seatH5DTO.getAlightingStationName().equals(req.getAlightingStationName());
        }).collect(Collectors.toList());
        Map<String, TrainProductH5DTO> maps = oldTrainProductH5DTOS.stream().collect(Collectors.toMap(TrainProductH5DTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));

        // 重复的产品列表
        List<TrainProductH5DTO> repeatProductList = new ArrayList<>();

        // 获取汇率
        MainDataCurrencyQueryDTO exchangeRate = getExchangeRateByCurrencyId(CurrencyIdCode.CNY.getCode());
        List<TrainProductH5DTO> trainProductH5DTO = new ArrayList<>();
        TrainTicketQueryReq queryReq = new TrainTicketQueryReq();
        queryReq.setDate(req.getDepartureDate().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        queryReq.setStart(ZhConverterUtil.toSimple(req.getBoardingStationName()));
        queryReq.setEnd(ZhConverterUtil.toSimple(req.getAlightingStationName()));
        List<ApiTrainProductDTO> list;
        try {
            list = iTrainApiService.getTrainTicketList(queryReq);
        } catch (Exception e) {
            log.error("api查询火车票异常", e);
            return oldTrainProductH5DTOS;
        }
        if (CollectionUtils.isEmpty(list)) {
            return oldTrainProductH5DTOS;
        }

//        // api 产品存redis
//        String key = getAliProductKey(queryReq.getDate(), req.getBoardingStationName(), req.getAlightingStationName());
//        redisTemplate.opsForValue().set(key, JSON.toJSONString(list));
        list = list.stream().filter(trainStation -> {
            // 过滤不符合的出发站,到达站
            return trainStation.getStation().equals(ZhConverterUtil.toSimple(req.getBoardingStationName()))
                    && trainStation.getEndstation().equals(ZhConverterUtil.toSimple(req.getAlightingStationName()));
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(list)) {
            return oldTrainProductH5DTOS;
        }
        list.forEach(trainStation -> {
            // 已有本产品跳过
            if (maps.containsKey(trainStation.getTrainno())) {
                repeatProductList.add(maps.get(trainStation.getTrainno()));
                return;
            }

            // 封装返回参数
            TrainProductH5DTO productH5DTO = new TrainProductH5DTO();
            productH5DTO.setDepartureTime(LocalTime.parse(trainStation.getDeparturetime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(req.getDepartureDate()));
            productH5DTO.setTerminusTime(LocalTime.parse(trainStation.getArrivaltime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(req.getDepartureDate()));
            productH5DTO.setRunningTime(trainStation.getCosttime());
            productH5DTO.setSupplierName("阿里云api");
            productH5DTO.setTrainNumberName(trainStation.getTrainno());
            productH5DTO.setProductSource(Constants.ALI);
            productH5DTO.setBoardingStationName(req.getBoardingStationName());
            productH5DTO.setAlightingStationName(req.getAlightingStationName());

            // 拆分座席
            List<ApiTrainProductSeatInfoDTO> seatlist = devideApiTrainProductToSeatInfo(trainStation);

            // 获取最低价格
            BigDecimal minPrice = seatlist.stream().map(ApiTrainProductSeatInfoDTO::getPrice).min(BigDecimal::compareTo).get();

            // 人民币转港币
            BigDecimal price = (minPrice.multiply(exchangeRate.getCrmExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP);
            price = roundPrice(price);
            productH5DTO.setPrice(price.setScale(0, BigDecimal.ROUND_UP));
            trainProductH5DTO.add(productH5DTO);
        });
//        oldTrainProductH5DTOS.removeAll(repeatProductList);
        trainProductH5DTO.addAll(repeatProductList);
        return trainProductH5DTO;
    }

    private List<TrainProductSeatH5DTO> buildAliTrainListPC(TrainAppQueryReq req, List<TrainProductSeatH5DTO> oldTrainProductSeatH5DTO) {
        oldTrainProductSeatH5DTO = oldTrainProductSeatH5DTO.stream().filter(seatH5DTO -> {
            // 过滤不符合的出发站,到达站
            return seatH5DTO.getBoardingStationName().equals(req.getBoardingStationName())
                    && seatH5DTO.getAlightingStationName().equals(req.getAlightingStationName());
        }).collect(Collectors.toList());

        Map<String, TrainProductSeatH5DTO> maps = oldTrainProductSeatH5DTO.stream().collect(Collectors.toMap(TrainProductSeatH5DTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
        List<TrainProductSeatH5DTO> newTrainProductSeatH5DTO = new ArrayList<>();

        // 重复的产品列表
        List<TrainProductSeatH5DTO> repeatProductList = new ArrayList<>();

        // 获取汇率
        MainDataCurrencyQueryDTO exchangeRate = getExchangeRateByCurrencyId(CurrencyIdCode.CNY.getCode());
        TrainTicketQueryReq queryReq = new TrainTicketQueryReq();
        queryReq.setDate(req.getDepartureDate().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        queryReq.setStart(ZhConverterUtil.toSimple(req.getBoardingStationName()));
        queryReq.setEnd(ZhConverterUtil.toSimple(req.getAlightingStationName()));
        List<ApiTrainProductDTO> list = new ArrayList<>();
        try {
            list = iTrainApiService.getTrainTicketList(queryReq);
        } catch (Exception e) {
            log.error("api查询火车票异常", e);
            return oldTrainProductSeatH5DTO;
        }
        if (CollectionUtils.isEmpty(list)) {
            return oldTrainProductSeatH5DTO;
        }
        list = list.stream().filter(trainStation -> {
            // 过滤不符合的出发站,到达站
            return trainStation.getStation().equals(ZhConverterUtil.toSimple(req.getBoardingStationName()))
                    && trainStation.getEndstation().equals(ZhConverterUtil.toSimple(req.getAlightingStationName()));
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(list)) {
            return oldTrainProductSeatH5DTO;
        }
        list.forEach(trainStation -> {
            // 封装返回参数
            TrainProductSeatH5DTO productSeatH5DTO;
            if (maps.containsKey(trainStation.getTrainno())) {
                productSeatH5DTO = maps.get(trainStation.getTrainno());
                repeatProductList.add(productSeatH5DTO);
            } else {
                productSeatH5DTO = new TrainProductSeatH5DTO();
                productSeatH5DTO.setDepartureTime(LocalTime.parse(trainStation.getDeparturetime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(req.getDepartureDate()));
                productSeatH5DTO.setTerminusTime(LocalTime.parse(trainStation.getArrivaltime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(req.getDepartureDate()));
                productSeatH5DTO.setRunningTime(trainStation.getCosttime());
                productSeatH5DTO.setSupplierName("阿里云api");
                productSeatH5DTO.setTrainNumberName(trainStation.getTrainno());
                productSeatH5DTO.setProductSource(Constants.ALI);
                productSeatH5DTO.setBoardingStationName(req.getBoardingStationName());
                productSeatH5DTO.setAlightingStationName(req.getAlightingStationName());
            }

            // 拆分座席
            List<ApiTrainProductSeatInfoDTO> seatlist = devideApiTrainProductToSeatInfo(trainStation);
            TrainProductSeatH5DTO finalProductSeatH5DTO = productSeatH5DTO;
            seatlist.forEach(seatInfo -> {
                List<TrainNumberSeatLevelCacheDTO> trainNumberSeatLevelCacheDTOS = finalProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS();
                if (CollectionUtils.isEmpty(trainNumberSeatLevelCacheDTOS)) {
                    finalProductSeatH5DTO.setTrainNumberSeatLevelCacheDTOS(new ArrayList<>());
                }
                TrainNumberSeatLevelCacheDTO seatLevelCacheDTO = new TrainNumberSeatLevelCacheDTO();
                seatLevelCacheDTO.setSeatLevelName(seatInfo.getSeatLevelName());
                seatLevelCacheDTO.setSeatNumber(seatInfo.getNum());
                seatLevelCacheDTO.setIsMtrProduct(MtrTrainNumber.getTrainNumberList().contains(trainStation.getTrainno()) ? 1 : 0);

                // 人民币转港币
                BigDecimal price = (seatInfo.getPrice().multiply(exchangeRate.getCrmExchangeRate())).setScale(2, BigDecimal.ROUND_HALF_UP);
                price = roundPrice(price);

                // 获取外挂系统列表 计算服务费
                List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList;
                if (seatLevelCacheDTO.getIsMtrProduct() == 1) {
                    mainDataManualSystemAppDTOList = getMtrSystemAppDTOList(exchangeRate.getCrmExchangeRate(), price);
                } else {
                    mainDataManualSystemAppDTOList = getDataManualSystemAppDTOList(exchangeRate.getCrmExchangeRate(), price);
                }
                seatLevelCacheDTO.setMainDataManualSystemAppDTOList(mainDataManualSystemAppDTOList);

                seatLevelCacheDTO.setPcPrice(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setPcChildPrice(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setH5Price(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setH5ChildPrice(price.setScale(0, BigDecimal.ROUND_UP));
                seatLevelCacheDTO.setIsAliProduct(1);
                finalProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS().add(seatLevelCacheDTO);
                newTrainProductSeatH5DTO.add(finalProductSeatH5DTO);
            });
        });
        oldTrainProductSeatH5DTO.removeAll(repeatProductList);
        newTrainProductSeatH5DTO.addAll(oldTrainProductSeatH5DTO);
        return newTrainProductSeatH5DTO.stream().filter(distinctByKey(TrainProductSeatH5DTO::getTrainNumberName)).collect(Collectors.toList());
    }

    //自定义根据对象属性过滤重复的对象
    private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 获取外挂系统列表
     *
     * @return
     */
    private List<MainDataManualSystemAppDTO> getDataManualSystemAppDTOList(BigDecimal crmRate, BigDecimal price) {
        List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList = new ArrayList<>();
        MainDataManualSystemAppDTO systemAppDTO = new MainDataManualSystemAppDTO();
        systemAppDTO.setId(MainDataManualSystemCode.MANUAL_2.getCode());
        systemAppDTO.setSupplierId(SupplierCode.SUPPLIER_2.getCode());
        systemAppDTO.setSupplierName(SupplierCode.SUPPLIER_2.getMsg());
        systemAppDTO.setSystemId(MainDataManualSystemCode.MANUAL_2.getCode());
        systemAppDTO.setSystemName(MainDataManualSystemCode.MANUAL_2.getMsg());
        systemAppDTO.setType(2);
        systemAppDTO.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        systemAppDTO.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
        systemAppDTO.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_2.getCode(), price, crmRate));
        systemAppDTO.setPrice(price.add(systemAppDTO.getServiceChargeAmount()).setScale(0, BigDecimal.ROUND_UP));
        mainDataManualSystemAppDTOList.add(systemAppDTO);
        MainDataManualSystemAppDTO systemAppDTO_2 = new MainDataManualSystemAppDTO();
        systemAppDTO_2.setId(MainDataManualSystemCode.MANUAL_1.getCode());
        systemAppDTO_2.setSupplierId(SupplierCode.SUPPLIER_1.getCode());
        systemAppDTO_2.setSupplierName(SupplierCode.SUPPLIER_1.getMsg());
        systemAppDTO_2.setSystemId(MainDataManualSystemCode.MANUAL_1.getCode());
        systemAppDTO_2.setSystemName(MainDataManualSystemCode.MANUAL_1.getMsg());
        systemAppDTO_2.setType(2);
        systemAppDTO_2.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        systemAppDTO_2.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
        systemAppDTO_2.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_1.getCode(), price, crmRate));
        systemAppDTO_2.setPrice(price.add(systemAppDTO_2.getServiceChargeAmount()).setScale(0, BigDecimal.ROUND_UP));
        mainDataManualSystemAppDTOList.add(systemAppDTO_2);
        return mainDataManualSystemAppDTOList;
    }

    /**
     * 获取外挂系统列表
     *
     * @return
     */
    private List<MainDataManualSystemAppDTO> getMtrSystemAppDTOList(BigDecimal crmRate, BigDecimal price) {
        List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList = new ArrayList<>();
        MainDataManualSystemAppDTO systemAppDTO = new MainDataManualSystemAppDTO();
        systemAppDTO.setId(MainDataManualSystemCode.MANUAL_3.getCode());
        systemAppDTO.setSupplierId(SupplierCode.SUPPLIER_3.getCode());
        systemAppDTO.setSupplierName(SupplierCode.SUPPLIER_3.getMsg());
        systemAppDTO.setSystemId(MainDataManualSystemCode.MANUAL_3.getCode());
        systemAppDTO.setSystemName(MainDataManualSystemCode.MANUAL_3.getMsg());
        systemAppDTO.setType(2);
        systemAppDTO.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
        systemAppDTO.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
        systemAppDTO.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_3.getCode(), price, crmRate));
        systemAppDTO.setPrice(BigDecimal.ZERO);
        mainDataManualSystemAppDTOList.add(systemAppDTO);
        return mainDataManualSystemAppDTOList;
    }

    /**
     * 【【火車票】阿里雲，價格小數2位小於0.5向上補0.5，大於0.5向上補1塊】
     * https://www.tapd.cn/42567854/bugtrace/bugs/view/1142567854001006212
     *
     * @param b
     * @return
     */
    private BigDecimal roundPrice(BigDecimal b) {
        BigDecimal fractionalPart = b.remainder(BigDecimal.ONE);
        if (fractionalPart.compareTo(new BigDecimal("0.5")) < 0) {
            b = b.setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal("0.5"));
        } else if (fractionalPart.compareTo(new BigDecimal("0.5")) > 0) {
            b = b.setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal("1"));
        }
        return b;
    }


    public static void main(String[] args) {
//        BigDecimal b = new BigDecimal("89.15");
//        BigDecimal c = new BigDecimal("89.55");
//        System.out.println(roundPrice(b));
//        System.out.println(roundPrice(c));
//        BigDecimal fractionalPart = b.remainder( BigDecimal.ONE ); // Result:  0.4523434
//        if (fractionalPart.compareTo(new BigDecimal("0.5")) < 0) {
//            b = b.setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal("0.5"));
////            System.out.println(b.setScale(0, BigDecimal.ROUND_DOWN));//返回结果：1.4
////            System.out.println(b.setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal("0.5")));
//        } else if (fractionalPart.compareTo(new BigDecimal("0.5")) > 0) {
//            b = b.setScale(0, BigDecimal.ROUND_DOWN).add(new BigDecimal("1"));
//        }
//        System.out.println(b);
//        System.out.println(b.scale());
//        System.out.println(fractionalPart);

//        String resultJson = "[{\"id\":\"63569891331932160\",\"productCode\":\"PG000000105251004292\",\"departureCityId\":\"1349239676838928386\",\"departureCityName\":\"深圳市\",\"arriveCityId\":\"1349239675089903621\",\"arriveCityName\":\"重慶市\",\"trainNumberId\":null,\"trainNumberName\":\"G320\",\"terminusTime\":\"2021-05-27 22:19:00\",\"departureTime\":\"2021-05-27 13:50:00\",\"estimatedTime\":null,\"boardingStationId\":\"63216343935090688\",\"boardingStationName\":\"深圳北\",\"alightingStationId\":\"63216343712792576\",\"alightingStationName\":\"肇庆东\",\"price\":0,\"supplierName\":null,\"productSource\":null,\"runningTime\":\"8小时29分\",\"trainStopStationCacheDTOS\":[{\"id\":\"63216343935090688\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1386239364564197377\",\"stationName\":\"深圳北\",\"arriveTime\":\"2021-05-24 13:50:00\",\"levelTime\":null,\"stopTime\":null},{\"id\":\"63216343654072320\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1390487378127024129\",\"stationName\":\"廣州南\",\"arriveTime\":\"2021-05-24 13:43:00\",\"levelTime\":\"2021-05-24 13:40:00\",\"stopTime\":\"3\"},{\"id\":\"63216343712792576\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1396653858975059969\",\"stationName\":\"肇庆东\",\"arriveTime\":\"2021-05-24 16:20:00\",\"levelTime\":\"2021-05-24 16:18:00\",\"stopTime\":\"2\"},{\"id\":\"63216343754735616\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1395187478996148225\",\"stationName\":\"桂林西\",\"arriveTime\":\"2021-05-24 18:05:00\",\"levelTime\":\"2021-05-24 18:01:00\",\"stopTime\":\"4\"},{\"id\":\"63216343800872960\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1396655152607465474\",\"stationName\":\"贵阳东\",\"arriveTime\":\"2021-05-24 20:10:00\",\"levelTime\":\"2021-05-24 20:06:00\",\"stopTime\":\"4\"},{\"id\":\"63216343847010304\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1396655239190482945\",\"stationName\":\"遵义\",\"arriveTime\":\"2021-05-24 21:01:00\",\"levelTime\":\"2021-05-24 20:59:00\",\"stopTime\":\"2\"},{\"id\":\"63216343888953344\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1396655274829484033\",\"stationName\":\"重庆西\",\"arriveTime\":\"2021-05-24 22:19:00\",\"levelTime\":\"2021-05-24 22:19:00\",\"stopTime\":\"0\"},{\"id\":\"63216343977033728\",\"trainNumberId\":\"63216343310139392\",\"stationId\":\"1396655274829484033\",\"stationName\":\"重庆西\",\"arriveTime\":null,\"levelTime\":\"2021-05-24 22:19:00\",\"stopTime\":null}],\"trainNumberSeatLevelCacheDTOS\":[{\"id\":\"63569891331932160\",\"seatLevelId\":\"3\",\"seatLevelName\":\"一等座\",\"seatNumber\":null,\"pcPrice\":667,\"pcChildPrice\":0,\"h5Price\":667,\"h5ChildPrice\":0,\"childNum\":0,\"adultNum\":0,\"serviceChargeType\":null,\"serviceChargePrice\":null,\"isAliProduct\":0,\"mainDataManualSystemAppDTOList\":null}]}]";
//        List<TrainProductSeatH5DTO> oldProduct = com.alibaba.fastjson.JSONArray.parseArray(resultJson, TrainProductSeatH5DTO.class);
//
//        Map<String, TrainProductSeatH5DTO> maps = oldProduct.stream().collect(Collectors.toMap(TrainProductSeatH5DTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
//
//
//        System.out.println(oldProduct);
//
//        String json = "{\"status\":0,\"msg\":\"ok\",\"result\":{\"start\":\"深圳北\",\"end\":\"重庆西\",\"date\":\"2021-05-31\",\"list\":[{\"trainno\":\"G320\",\"type\":\"G\",\"typename\":\"高铁\",\"station\":\"深圳北\",\"endstation\":\"重庆西\",\"departuretime\":\"15:10\",\"arrivaltime\":\"22:19\",\"costtime\":\"7小时9分\",\"trainno12306\":\"\",\"distance\":0,\"day\":1,\"isend\":1,\"sequenceno\":1,\"stationcode\":\"IOQ\",\"endstationcode\":\"CXW\",\"departstation\":\"深圳北\",\"terminalstation\":\"重庆西\",\"departstationcode\":\"IOQ\",\"terminalstationcode\":\"CXW\",\"startdate\":\"20210531\",\"canbuy\":\"N\",\"priceed\":519.5,\"numed\":\"有\",\"priceyd\":811.5,\"numyd\":\"有\",\"pricesw\":1533.5,\"numsw\":\"2\",\"pricetd\":\"-\",\"numtd\":\"-\",\"pricerz\":\"-\",\"numrz\":\"-\",\"priceyz\":\"-\",\"numyz\":\"-\",\"pricegr1\":\"-\",\"numgr1\":\"-\",\"pricegr2\":\"-\",\"numgr2\":\"-\",\"pricerw1\":\"-\",\"numrw1\":\"-\",\"pricerw2\":\"-\",\"numrw2\":\"-\",\"priceyw1\":\"-\",\"numyw1\":\"-\",\"priceyw2\":\"-\",\"numyw2\":\"-\",\"priceyw3\":\"-\",\"numyw3\":\"-\",\"pricewz\":\"-\",\"numwz\":\"-\",\"priceqt\":\"-\",\"numqt\":\"-\",\"pricedw\":\"-\",\"numdw\":\"-\",\"pricedw1\":\"-\",\"numdw1\":\"-\"}]}}";
////        System.out.println(json);
//        JSONObject jsonObject = new JSONObject(json);
//        JSONObject result = jsonObject.getJSONObject("result");
//        JSONArray list = result.getJSONArray("list");
//        System.out.println("getTrainTicketList=============================================================");
//        List<ApiTrainProductDTO> list1 = JSONUtil.toList(list, ApiTrainProductDTO.class);
//        System.out.println(list1);
//
//        String req = "{\"boardingStationName\":\"深圳北\",\"alightingStationName\":\"重慶西1\",\"adultNum\":1,\"hovered\":false,\"childrenNum\":0,\"weekday\":\"\",\"departureDate\":\"2021-05-31\"}";
//        TrainAppQueryReq queryReq = com.alibaba.fastjson.JSONObject.parseObject(req, TrainAppQueryReq.class);
//
//
//        list1 = list1.stream().filter(trainStation -> {
//            // 过滤不符合的出发站,到达站
//            return trainStation.getStation().equals(ZhConverterUtil.toSimple(queryReq.getBoardingStationName()))
//                            && trainStation.getEndstation().equals(ZhConverterUtil.toSimple(queryReq.getAlightingStationName()));
//        }).collect(Collectors.toList());
//
//        System.out.println(list1);

//        List<TrainProductSeatH5DTO> newTrainProductSeatH5DTO = new ArrayList<>();
//
//        list1.stream().filter(trainStation -> {
//            // 过滤不符合的出发站,到达站
//            return trainStation.getStation().equals("深圳北")
//                    && trainStation.getEndstation().equals("肇庆东");
//        }).forEach(trainStation -> {
//            TrainProductSeatH5DTO productSeatH5DTO = null;
//            if (maps.containsKey(trainStation.getTrainno())) {
//                productSeatH5DTO = maps.get(trainStation.getTrainno());
//            } else {
//                productSeatH5DTO = new TrainProductSeatH5DTO();
//                productSeatH5DTO.setDepartureTime(LocalTime.parse(trainStation.getDeparturetime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(LocalDate.of(2021, 5, 27)));
//                productSeatH5DTO.setTerminusTime(LocalTime.parse(trainStation.getArrivaltime(), DateTimeFormatter.ofPattern("HH:mm")).atDate(LocalDate.of(2021, 5, 27)));
//                productSeatH5DTO.setRunningTime(trainStation.getCosttime());
//                productSeatH5DTO.setSupplierName("阿里云api");
//                productSeatH5DTO.setTrainNumberName(trainStation.getTrainno());
//                productSeatH5DTO.setProductSource(Constants.ALI);
//                productSeatH5DTO.setBoardingStationName(trainStation.getStation());
//                productSeatH5DTO.setAlightingStationName(trainStation.getEndstation());
//            }
//
//            // 拆分座席
//            TrainProductAppAndPcServiceImpl impl = new TrainProductAppAndPcServiceImpl();
//            List<ApiTrainProductSeatInfoDTO> seatlist = impl.devideApiTrainProductToSeatInfo(trainStation);
//            TrainProductSeatH5DTO finalProductSeatH5DTO = productSeatH5DTO;
//            seatlist.forEach(seatInfo -> {
//                List<TrainNumberSeatLevelCacheDTO> trainNumberSeatLevelCacheDTOS = finalProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS();
//                if (CollectionUtils.isEmpty(trainNumberSeatLevelCacheDTOS)) {
//                    finalProductSeatH5DTO.setTrainNumberSeatLevelCacheDTOS(new ArrayList<>());
//                }
//                TrainNumberSeatLevelCacheDTO seatLevelCacheDTO = new TrainNumberSeatLevelCacheDTO();
//                seatLevelCacheDTO.setSeatLevelName(seatInfo.getSeatLevelName());
//                seatLevelCacheDTO.setSeatNumber(seatInfo.getNum());
//
//                // 计算服务费
//                List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList = new ArrayList<>();
//                MainDataManualSystemAppDTO systemAppDTO = new MainDataManualSystemAppDTO();
//                systemAppDTO.setId(MainDataManualSystemCode.MANUAL_1.getCode());
//                systemAppDTO.setSupplierId(SupplierCode.SUPPLIER_1.getCode());
//                systemAppDTO.setSupplierName(SupplierCode.SUPPLIER_1.getMsg());
//                systemAppDTO.setSystemName(MainDataManualSystemCode.MANUAL_1.getMsg());
//                systemAppDTO.setType(2);
//                systemAppDTO.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
//                systemAppDTO.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
//                systemAppDTO.setServiceChargeAmount(new BigDecimal(0));
//                mainDataManualSystemAppDTOList.add(systemAppDTO);
//                MainDataManualSystemAppDTO systemAppDTO_2 = new MainDataManualSystemAppDTO();
//                systemAppDTO_2.setId(MainDataManualSystemCode.MANUAL_1.getCode());
//                systemAppDTO_2.setSupplierId(SupplierCode.SUPPLIER_1.getCode());
//                systemAppDTO_2.setSupplierName(SupplierCode.SUPPLIER_1.getMsg());
//                systemAppDTO_2.setSystemName(MainDataManualSystemCode.MANUAL_1.getMsg());
//                systemAppDTO_2.setType(2);
//                systemAppDTO_2.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
//                systemAppDTO_2.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
//                systemAppDTO_2.setServiceChargeAmount(new BigDecimal(0));
//                mainDataManualSystemAppDTOList.add(systemAppDTO_2);
//                seatLevelCacheDTO.setMainDataManualSystemAppDTOList(mainDataManualSystemAppDTOList);
////                MathContext context = new MathContext(2, RoundingMode.HALF_DOWN);
//                BigDecimal price = (seatInfo.getPrice().multiply(new BigDecimal("1.19670"))).setScale(2, BigDecimal.ROUND_HALF_UP);
//                System.out.println(seatInfo.getPrice());
//                System.out.println(price);
////                BigDecimal price = seatInfo.getPrice();
//                seatLevelCacheDTO.setPcPrice(price);
//                seatLevelCacheDTO.setPcChildPrice(price);
//                seatLevelCacheDTO.setH5Price(price);
//                seatLevelCacheDTO.setH5ChildPrice(price);
//                seatLevelCacheDTO.setIsAliProduct(1);
//                finalProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS().add(seatLevelCacheDTO);
//                newTrainProductSeatH5DTO.add(finalProductSeatH5DTO);
//                BigDecimal min = finalProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS().stream().map(TrainNumberSeatLevelCacheDTO::getPcPrice).min(BigDecimal::compareTo).get();
//                System.out.println("--->" + min);
//
//            });
//        });
//
//
//        System.out.println("----->" + JSON.toJSONString(newTrainProductSeatH5DTO));
    }


    private String getAliProductKey(String date, String start, String end) {
        return RedisConstants.TRAIN_ALI_PRODUCT + date + "-" +
                start + "-" + end;
    }

    /**
     * 拆分座席数据
     *
     * @param apiTrainProductDTO
     * @return
     */
    private List<ApiTrainProductSeatInfoDTO> devideApiTrainProductToSeatInfo(ApiTrainProductDTO apiTrainProductDTO) {
        List<ApiTrainProductSeatInfoDTO> list = new ArrayList<>();
        try {
            Class<? extends ApiTrainProductDTO> aClass = apiTrainProductDTO.getClass();
            Method[] methods = aClass.getDeclaredMethods();
            for (Method method : methods) {
                String methodName = method.getName();
                if (methodName.startsWith("getPrice")) {
                    String suffix = methodName.substring(methodName.indexOf("getPrice") + 8);
                    String price = (String) method.invoke(apiTrainProductDTO);
                    // 查询票价,如果为"-"代表没有该座次
                    if ("-".equals(price)) {
                        continue;
                    }
                    ApiTrainProductSeatInfoDTO apiTrainProductSeatInfoDTO = new ApiTrainProductSeatInfoDTO();
                    apiTrainProductSeatInfoDTO.setPrice(new BigDecimal(price));
                    String seatLevelName = SeatAliApiEnum.getName(suffix);
                    apiTrainProductSeatInfoDTO.setSeatLevelName(seatLevelName);
                    // 有票价查询余票数
                    Method declaredMethod = aClass.getDeclaredMethod("getNum" + suffix);
                    String num = (String) declaredMethod.invoke(apiTrainProductDTO);
                    apiTrainProductSeatInfoDTO.setNum(num);
                    list.add(apiTrainProductSeatInfoDTO);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return list;
    }

    @DubboReference
    IMainDataManualSystemService mainDataManualSystemService;

    @Override
    public Result<TrainProductSeatH5DTO> seatQuery(String productCode) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (productCode == null) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14002);
        }
        boolQuery.must(QueryBuilders.matchQuery("trainProductCacheDTOS.productCode", productCode));
        sourceBuilder.query(boolQuery);

        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_INDEX).source(sourceBuilder);
        List<TrainProductCacheDTO> trainProductList = new ArrayList<>();
        Map<String, TrainNumberCacheDTO> trainNumberCacheDTOMap = new HashMap<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<TrainNumberCacheDTO> trainNumberCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                TrainNumberCacheDTO busLineCacheDTO = JSON.parseObject(sourceAsString, TrainNumberCacheDTO.class);
                trainNumberCacheDTOS.add(busLineCacheDTO);
            }
            if (trainNumberCacheDTOS != null && trainNumberCacheDTOS.size() > 0) {
                trainNumberCacheDTOMap = trainNumberCacheDTOS.stream().collect(Collectors.toMap(TrainNumberCacheDTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
                trainNumberCacheDTOS.forEach(line -> {
                    trainProductList.addAll(line.getTrainProductCacheDTOS());
                });
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }
        Map<String, TrainProductCacheDTO> maps = trainProductList.stream().collect(Collectors.toMap(TrainProductCacheDTO::getProductCode, Function.identity(), (key1, key2) -> key2));
        List<TrainProductSeatH5DTO> trainProductH5DTOS = EntityUtil.copyList(trainProductList, TrainProductSeatH5DTO.class);
        for (TrainProductSeatH5DTO trainH5DTO : trainProductH5DTOS) {
            trainH5DTO.setPrice(maps.get(trainH5DTO.getProductCode()).getTrainNumberSeatLevelCacheDTOS().get(0).getH5ChildPrice());
            trainH5DTO.setTrainStopStationCacheDTOS(trainNumberCacheDTOMap.get(trainH5DTO.getTrainNumberName()).getTrainStopStationCacheDTOS());
            trainH5DTO.setTrainNumberSeatLevelCacheDTOS(trainNumberCacheDTOMap.get(trainH5DTO.getTrainNumberName()).getTrainProductCacheDTOS().get(0).getTrainNumberSeatLevelCacheDTOS());
        }
        TrainProductSeatH5DTO seatH5DTO = trainProductH5DTOS.get(0);

        // 获取阿里坐席列表
        String key = getAliProductKey(null, seatH5DTO.getBoardingStationName(), seatH5DTO.getAlightingStationName());
        String result = redisTemplate.opsForValue().get(key);
        if (result != null) {
            List<ApiTrainProductSeatInfoDTO> seatlist = JSON.parseArray(redisTemplate.opsForValue().get(key), ApiTrainProductSeatInfoDTO.class);

            // 拆分座席
            seatlist.forEach(seatInfo -> {
                if (seatH5DTO.getTrainNumberName().equals(seatInfo.getTrainno())) {
                    List<TrainNumberSeatLevelCacheDTO> trainNumberSeatLevelCacheDTOS = seatH5DTO.getTrainNumberSeatLevelCacheDTOS();
                    if (CollectionUtils.isEmpty(trainNumberSeatLevelCacheDTOS)) {
                        seatH5DTO.setTrainNumberSeatLevelCacheDTOS(new ArrayList<>());
                    }
                    TrainNumberSeatLevelCacheDTO seatLevelCacheDTO = new TrainNumberSeatLevelCacheDTO();
                    seatLevelCacheDTO.setSeatLevelName(seatInfo.getSeatLevelName());
                    seatLevelCacheDTO.setSeatNumber(seatInfo.getNum());

                    // 计算服务费
                    MainDataCurrencyQueryDTO exchangeRate =
                            getExchangeRateByCurrencyId(CurrencyIdCode.CNY.getCode());
                    List<MainDataManualSystemAppDTO> mainDataManualSystemAppDTOList = new ArrayList<>();
                    MainDataManualSystemAppDTO systemAppDTO = new MainDataManualSystemAppDTO();
                    systemAppDTO.setId(MainDataManualSystemCode.MANUAL_1.getCode());
                    systemAppDTO.setSupplierId(SupplierCode.SUPPLIER_1.getCode());
                    systemAppDTO.setSupplierName(SupplierCode.SUPPLIER_1.getMsg());
                    systemAppDTO.setSystemName(MainDataManualSystemCode.MANUAL_1.getMsg());
                    systemAppDTO.setType(2);
                    systemAppDTO.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
                    systemAppDTO.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
                    systemAppDTO.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_1.getCode(), seatInfo.getPrice(), exchangeRate.getCrmExchangeRate()));
                    mainDataManualSystemAppDTOList.add(systemAppDTO);
                    MainDataManualSystemAppDTO systemAppDTO_2 = new MainDataManualSystemAppDTO();
                    systemAppDTO_2.setId(MainDataManualSystemCode.MANUAL_1.getCode());
                    systemAppDTO_2.setSupplierId(SupplierCode.SUPPLIER_1.getCode());
                    systemAppDTO_2.setSupplierName(SupplierCode.SUPPLIER_1.getMsg());
                    systemAppDTO_2.setSystemName(MainDataManualSystemCode.MANUAL_1.getMsg());
                    systemAppDTO_2.setType(2);
                    systemAppDTO_2.setBusinessTypeId(SystemBusinessType.TRAIN_TICKET.getCode());
                    systemAppDTO_2.setBusinessTypeName(SystemBusinessType.TRAIN_TICKET.getValue());
                    systemAppDTO_2.setServiceChargeAmount(getServiceChargeAmount(MainDataManualSystemCode.MANUAL_2.getCode(), seatInfo.getPrice(), exchangeRate.getCrmExchangeRate()));
                    mainDataManualSystemAppDTOList.add(systemAppDTO_2);
                    seatLevelCacheDTO.setMainDataManualSystemAppDTOList(mainDataManualSystemAppDTOList);
                    seatLevelCacheDTO.setPcPrice(seatInfo.getPrice().divide(exchangeRate.getCrmExchangeRate()));
                    seatLevelCacheDTO.setPcChildPrice(seatInfo.getPrice().divide(exchangeRate.getCrmExchangeRate()));
                    seatLevelCacheDTO.setH5Price(seatInfo.getPrice().divide(exchangeRate.getCrmExchangeRate()));
                    seatLevelCacheDTO.setH5ChildPrice(seatInfo.getPrice().divide(exchangeRate.getCrmExchangeRate()));
                    seatLevelCacheDTO.setIsAliProduct(1);
                    seatH5DTO.getTrainNumberSeatLevelCacheDTOS().add(seatLevelCacheDTO);
                }
            });
        }

        return Result.success(trainProductH5DTOS.get(0));
    }

    @Override
    public Result<List<TrainProductSeatH5DTO>> reservationQueryPc(TrainAppQueryReq req) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (req == null) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14002);
        }

        // 上车站
        if (req.getBoardingStationName() != null) {
            boolQuery.filter(QueryBuilders.matchPhraseQuery("trainProductCacheDTOS.boardingStationName", req.getBoardingStationName()));
        }

        // 下车站
        if (req.getAlightingStationName() != null) {
            boolQuery.filter(QueryBuilders.matchPhraseQuery("trainProductCacheDTOS.alightingStationName", req.getAlightingStationName()));
        }

        // 出发日期
        if (req.getDepartureDate() != null) {
            RangeQueryBuilder startQueryBuilder = QueryBuilders.rangeQuery("trainProductCacheDTOS.channelSaleCacheList.dateBegin");
            RangeQueryBuilder endQueryBuilder = QueryBuilders.rangeQuery("trainProductCacheDTOS.channelSaleCacheList.dateEnd");
            startQueryBuilder.lte(req.getDepartureDate());
            endQueryBuilder.gte(req.getDepartureDate());
            boolQuery.must(startQueryBuilder);
            boolQuery.must(endQueryBuilder);
        }
        sourceBuilder.query(boolQuery);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_INDEX).source(sourceBuilder);
        List<TrainProductCacheDTO> trainProductList = new ArrayList<>();
        Map<String, TrainNumberCacheDTO> trainNumberCacheDTOMap = new HashMap<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<TrainNumberCacheDTO> trainNumberCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                TrainNumberCacheDTO busLineCacheDTO = JSON.parseObject(sourceAsString, TrainNumberCacheDTO.class);
                trainNumberCacheDTOS.add(busLineCacheDTO);
            }
            if (trainNumberCacheDTOS.size() > 0) {
                trainNumberCacheDTOMap = trainNumberCacheDTOS.stream().collect(Collectors.toMap(TrainNumberCacheDTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
                trainNumberCacheDTOS.forEach(line -> {
                    trainProductList.addAll(line.getTrainProductCacheDTOS());
                });
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }
        Map<String, TrainProductCacheDTO> maps = trainProductList.stream().collect(Collectors.toMap(TrainProductCacheDTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
        List<TrainProductSeatH5DTO> trainProductH5DTOS = EntityUtil.copyList(trainProductList, TrainProductSeatH5DTO.class);

        // 获取阿里云api产品信息
        trainProductH5DTOS = buildAliTrainListPC(req, trainProductH5DTOS);
        List<TrainProductSeatH5DTO> newTrainProductSeatH5DTO = new ArrayList<>();
        for (TrainProductSeatH5DTO trainH5DTO : trainProductH5DTOS) {
            // 获取最低价格
            BigDecimal price = trainH5DTO.getTrainNumberSeatLevelCacheDTOS().stream().map(TrainNumberSeatLevelCacheDTO::getPcChildPrice).min(BigDecimal::compareTo).get();
            trainH5DTO.setPrice(price);
            trainH5DTO.setRunningTime(convertRunningTime(trainH5DTO.getDepartureTime(), trainH5DTO.getTerminusTime()));
            if (trainNumberCacheDTOMap.containsKey(trainH5DTO.getTrainNumberName())) {
                trainH5DTO.setTrainStopStationCacheDTOS(trainNumberCacheDTOMap.get(trainH5DTO.getTrainNumberName()).getTrainStopStationCacheDTOS());
            }

            // 出发时间
            LocalTime departureTime = trainH5DTO.getDepartureTime().toLocalTime();

            // 产品筛选
            boolean flag = false;
            boolean timeIntervalFlag = false;
            if (trainH5DTO.getAlightingStationName().equals(req.getAlightingStationName()) && trainH5DTO.getBoardingStationName().equals(req.getBoardingStationName())) {
                // 是否为高速列车筛选
                if (req.getIsExpressTrain() == 1) {
                    if (trainH5DTO.getTrainNumberName().startsWith("D") || trainH5DTO.getTrainNumberName().startsWith("G") || trainH5DTO.getTrainNumberName().startsWith("C")) {
                        newTrainProductSeatH5DTO.add(trainH5DTO);
                    }
                } else {
                    if (CollectionUtils.isEmpty(req.getTypeIds())) {
                        flag = true;
                    } else {
                        // 车次类型筛选
                        for (Long typeId : req.getTypeIds()) {
                            if (typeId == TrainNumberType.GC_HIGH.getCode()) {
                                if (trainH5DTO.getTrainNumberName().startsWith("G") || trainH5DTO.getTrainNumberName().startsWith("C")) {
                                    flag = true;
                                    break;
                                }
                            } else if (typeId == TrainNumberType.D_TRAIN.getCode()) {
                                if (trainH5DTO.getTrainNumberName().startsWith("D")) {
                                    flag = true;
                                    break;
                                }
                            } else if (typeId == TrainNumberType.ORDINARY_TRAIN.getCode()) {
                                if (!trainH5DTO.getTrainNumberName().startsWith("D") && !trainH5DTO.getTrainNumberName().startsWith("G") && !trainH5DTO.getTrainNumberName().startsWith("C")) {
                                    flag = true;
                                    break;
                                }
                            }
                        }
                    }
                    if (CollectionUtils.isEmpty(req.getDepartureTimeAppQueryReqs())) {
                        timeIntervalFlag = true;
                    } else {
                        // 出发时间筛选
                        for (TrainDepartureTimeAppQueryReq timeAppQueryReq : req.getDepartureTimeAppQueryReqs()) {
                            timeIntervalFlag = inTheTimeInterval(departureTime, timeAppQueryReq.getStartTime(), timeAppQueryReq.getEndTime());
                            if (timeIntervalFlag) {
                                break;
                            }
                        }
                    }

                    if (timeIntervalFlag && flag) {
                        newTrainProductSeatH5DTO.add(trainH5DTO);
                    }
                }
            }
        }
        return Result.success(newTrainProductSeatH5DTO);
    }

    /**
     * 判断时分是否在区间之内
     *
     * @param localTime
     * @param startTime
     * @param endTime
     * @return
     */
    private static boolean inTheTimeInterval(LocalTime localTime, LocalTime startTime, LocalTime endTime) {
        LocalTime toLocalTime = LocalTime.of(localTime.getHour(), localTime.getMinute());

        log.info("localTime{}, startTime:{}, endTime:{} " + localTime.toString(), startTime.toString(), endTime.toString());
        if (toLocalTime.equals(startTime) || toLocalTime.equals(endTime)) {
            return true;
        }
        return toLocalTime.isAfter(startTime) && toLocalTime.isBefore(endTime);
    }

    @Override
    public Result<List<MainDataStationCacheDTO>> query(String stationName) {
        if (StringUtils.isEmpty(stationName)) {
            return Result.success(new ArrayList<>());
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        stationName = ZhConverterUtil.toTraditional(stationName);
        WildcardQueryBuilder queryBuilder = QueryBuilders.wildcardQuery("stationName", "*" + stationName + "*");
        sourceBuilder.query(queryBuilder);
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_STATION_INDEX).source(sourceBuilder);
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<MainDataStationCacheDTO> mainDataStationCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                MainDataStationCacheDTO mainDataStationCacheDTO = JSON.parseObject(sourceAsString, MainDataStationCacheDTO.class);
                mainDataStationCacheDTOS.add(mainDataStationCacheDTO);
            }
            return Result.success(mainDataStationCacheDTOS);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }
    }

    @Override
    public Result<TrainProductDetailPcDTO> queryDetail(TrainDetailAppQueryReq req) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (req == null) {
            throw new BusinessException(SystemError.TRAIN_PRODUCT_14002);
        }
        boolQuery.must(QueryBuilders.matchQuery("trainProductCacheDTOS.trainNumberSeatLevelCacheDTOS.id", req.getId()));
        sourceBuilder.query(boolQuery);

        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_INDEX).source(sourceBuilder);
        List<TrainProductCacheDTO> trainProductList = new ArrayList<>();
        Map<String, TrainNumberCacheDTO> trainNumberCacheDTOMap = new HashMap<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<TrainNumberCacheDTO> trainNumberCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                TrainNumberCacheDTO busLineCacheDTO = JSON.parseObject(sourceAsString, TrainNumberCacheDTO.class);
                trainNumberCacheDTOS.add(busLineCacheDTO);
            }
            if (trainNumberCacheDTOS.size() > 0) {
                trainNumberCacheDTOMap = trainNumberCacheDTOS.stream().collect(Collectors.toMap(TrainNumberCacheDTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
                trainNumberCacheDTOS.forEach(line -> {
                    trainProductList.addAll(line.getTrainProductCacheDTOS());
                });
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }


        Map<String, TrainProductCacheDTO> maps = trainProductList.stream().collect(Collectors.toMap(TrainProductCacheDTO::getProductCode, Function.identity(), (key1, key2) -> key2));
        List<TrainProductDetailPcDTO> trainProductDetailPcDTOS = EntityUtil.copyList(trainProductList, TrainProductDetailPcDTO.class);
        for (TrainProductDetailPcDTO detailPcDTO : trainProductDetailPcDTOS) {
            detailPcDTO.setPrice(maps.get(detailPcDTO.getProductCode()).getTrainNumberSeatLevelCacheDTOS().get(0).getH5ChildPrice());
            detailPcDTO.setTrainStopStationCacheDTOS(trainNumberCacheDTOMap.get(detailPcDTO.getTrainNumberName()).getTrainStopStationCacheDTOS());
            for (TrainNumberSeatLevelCacheDTO seatLevelCacheDTO : detailPcDTO.getTrainNumberSeatLevelCacheDTOS()) {
                if (seatLevelCacheDTO.getId().equals(req.getId())) {
                    seatLevelCacheDTO.setChildNum(req.getChildNum());
                    seatLevelCacheDTO.setAdultNum(req.getAdultNum());

                    detailPcDTO.setTrainNumberSeatLevelCacheDTOS(Collections.singletonList(seatLevelCacheDTO));

                    // 成人单票价格 + 服务费
                    BigDecimal adultChargePrice = null;

                    // 小童单票价格 + 服务费
                    BigDecimal childChargePrice = null;
                    if (Objects.equals(seatLevelCacheDTO.getServiceChargeType(), ServiceChargeType.PERCENTAGE.getCode())) {
                        BigDecimal percentage = seatLevelCacheDTO.getServiceChargePrice().divide(new BigDecimal("100"));
                        adultChargePrice = seatLevelCacheDTO.getPcPrice().multiply(percentage);
                        childChargePrice = seatLevelCacheDTO.getPcChildPrice().multiply(percentage);
                    } else if (Objects.equals(seatLevelCacheDTO.getServiceChargeType(), ServiceChargeType.FIXED.getCode())) {
                        adultChargePrice = seatLevelCacheDTO.getPcPrice().add(seatLevelCacheDTO.getServiceChargePrice());
                        childChargePrice = seatLevelCacheDTO.getPcChildPrice().add(seatLevelCacheDTO.getServiceChargePrice());
                    } else {
                        throw new BusinessException(SystemError.TRAIN_PRODUCT_14035);
                    }
                    BigDecimal price = adultChargePrice.multiply(BigDecimal.valueOf(req.getAdultNum())).add(childChargePrice.multiply(BigDecimal.valueOf(req.getChildNum())));

                    // 价格为总价
                    detailPcDTO.setPrice(price);
                }
            }
        }

        return Result.success(trainProductDetailPcDTOS.get(0));
    }

    @Override
    public Result stationInit() {
        // 清除旧数据
        stationElasticSearchMapper.deleteAll();

        //  站点信息es
        List<MainDataStationDTO> mainDataStationDTOList = mainDataStationService.listAll();
        List<MainDataStationCacheDTO> stationCacheDTOList = EntityUtil.copyList(mainDataStationDTOList, MainDataStationCacheDTO.class);
        List<MainDataStationCache> mainDataStationCaches = EntityUtil.copyList(stationCacheDTOList, MainDataStationCache.class);
        stationElasticSearchMapper.saveAll(mainDataStationCaches);
        return Result.success();
    }

    @Override
    public Result<TrainProductSeatH5DTO> seatQueryWithAli(TrainSeatAppQueryReq req) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.matchQuery("trainNumberName", req.getTrainNumberName()));
        sourceBuilder.query(boolQuery);

        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_INDEX).source(sourceBuilder);
        List<TrainProductCacheDTO> trainProductList = new ArrayList<>();
        Map<String, TrainNumberCacheDTO> trainNumberCacheDTOMap = new HashMap<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<TrainNumberCacheDTO> trainNumberCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                TrainNumberCacheDTO busLineCacheDTO = JSON.parseObject(sourceAsString, TrainNumberCacheDTO.class);
                trainNumberCacheDTOS.add(busLineCacheDTO);
            }
            if (trainNumberCacheDTOS.size() > 0) {
                trainNumberCacheDTOMap = trainNumberCacheDTOS.stream().collect(Collectors.toMap(TrainNumberCacheDTO::getTrainNumberName, Function.identity(), (key1, key2) -> key2));
                trainNumberCacheDTOS.forEach(line -> {
                    trainProductList.addAll(line.getTrainProductCacheDTOS());
                });
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }

        // 过滤不符合的出发站,到达站
        List<TrainProductCacheDTO> newTrainProductList = trainProductList.stream().filter(trainStation -> {
            return trainStation.getBoardingStationName().equals(req.getBoardingStationName())
                    && trainStation.getAlightingStationName().equals(req.getAlightingStationName());
        }).collect(Collectors.toList());
        List<TrainProductSeatH5DTO> productSeatH5DTOS = EntityUtil.copyList(newTrainProductList, TrainProductSeatH5DTO.class);

        // 获取阿里云产品
        TrainAppQueryReq appQueryReq = new TrainAppQueryReq();
        appQueryReq.setBoardingStationName(req.getBoardingStationName());
        appQueryReq.setAlightingStationName(req.getAlightingStationName());
        appQueryReq.setDepartureDate(req.getDepartureDate());
        productSeatH5DTOS = buildAliTrainListPC(appQueryReq, productSeatH5DTOS);
        productSeatH5DTOS = productSeatH5DTOS.stream().filter(trainStation -> {
            return trainStation.getBoardingStationName().equals(req.getBoardingStationName())
                    && trainStation.getAlightingStationName().equals(req.getAlightingStationName())
                    && trainStation.getTrainNumberName().equals(req.getTrainNumberName());
        }).collect(Collectors.toList());
        TrainProductSeatH5DTO trainProductSeatH5DTO = productSeatH5DTOS.get(0);
        BigDecimal price = trainProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS().stream().map(TrainNumberSeatLevelCacheDTO::getH5ChildPrice).min(BigDecimal::compareTo).get();

        // 获取最低价格
        trainProductSeatH5DTO.setPrice(price);
        return Result.success(productSeatH5DTOS.get(0));
    }

    @Override
    public Result<TrainProductDetailPcDTO> queryDetailWithAli(TrainDetailAppQueryReq req) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.matchQuery("trainNumberName", req.getTrainNumberName()));
        sourceBuilder.query(boolQuery);

        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRAIN_INDEX).source(sourceBuilder);
        List<TrainProductCacheDTO> trainProductList = new ArrayList<>();
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = response.getHits();
            List<TrainNumberCacheDTO> trainNumberCacheDTOS = new ArrayList<>();
            for (SearchHit hit : hits.getHits()) {
                String sourceAsString = hit.getSourceAsString();
                TrainNumberCacheDTO busLineCacheDTO = JSON.parseObject(sourceAsString, TrainNumberCacheDTO.class);
                trainNumberCacheDTOS.add(busLineCacheDTO);
            }
            if (trainNumberCacheDTOS.size() > 0) {
                trainNumberCacheDTOS.forEach(line -> {
                    trainProductList.addAll(line.getTrainProductCacheDTOS());
                });
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }

        // 过滤不符合的出发站,到达站
        List<TrainProductCacheDTO> newTrainProductList = trainProductList.stream().filter(trainStation -> {
            return trainStation.getBoardingStationName().equals(req.getBoardingStationName())
                    && trainStation.getAlightingStationName().equals(req.getAlightingStationName());
        }).collect(Collectors.toList());
        List<TrainProductSeatH5DTO> productSeatH5DTOS = EntityUtil.copyList(newTrainProductList, TrainProductSeatH5DTO.class);

        // 获取阿里云产品
        TrainAppQueryReq appQueryReq = new TrainAppQueryReq();
        appQueryReq.setBoardingStationName(req.getBoardingStationName());
        appQueryReq.setAlightingStationName(req.getAlightingStationName());
        appQueryReq.setDepartureDate(req.getDepartureDate());
        productSeatH5DTOS = buildAliTrainListPC(appQueryReq, productSeatH5DTOS);
        productSeatH5DTOS = productSeatH5DTOS.stream().filter(trainStation -> {
            return trainStation.getBoardingStationName().equals(req.getBoardingStationName())
                    && trainStation.getAlightingStationName().equals(req.getAlightingStationName())
                    && trainStation.getTrainNumberName().equals(req.getTrainNumberName());
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(productSeatH5DTOS)) {
            return Result.success(null);
        }

        TrainProductSeatH5DTO trainProductSeatH5DTO = productSeatH5DTOS.get(0);

        // 选定坐席等级
        List<TrainNumberSeatLevelCacheDTO> trainNumberSeatLevelCacheDTOS = trainProductSeatH5DTO.getTrainNumberSeatLevelCacheDTOS().stream().filter(productSeat -> {
            return productSeat.getSeatLevelName().equals(req.getSeatLevelName()) ||
                    ZhConverterUtil.toTraditional(productSeat.getSeatLevelName()).equals(req.getSeatLevelName());
        }).collect(Collectors.toList());
        trainProductSeatH5DTO.setTrainNumberSeatLevelCacheDTOS(trainNumberSeatLevelCacheDTOS);
        TrainProductDetailPcDTO detailPcDTO = EntityUtil.copy(trainProductSeatH5DTO, TrainProductDetailPcDTO.class);
        for (TrainNumberSeatLevelCacheDTO seatLevelCacheDTO : detailPcDTO.getTrainNumberSeatLevelCacheDTOS()) {
            // 阿里云产品
            if (seatLevelCacheDTO.getIsAliProduct() == 1 && !StringUtils.isEmpty(req.getSystemId())) {
                BigDecimal serviceChargePrice = BigDecimal.ZERO;
                for (MainDataManualSystemAppDTO system : seatLevelCacheDTO.getMainDataManualSystemAppDTOList()) {
                    if (system.getId().equals(req.getSystemId())) {
                        serviceChargePrice = system.getServiceChargeAmount();
                    }
                }
                seatLevelCacheDTO.setServiceChargePrice(serviceChargePrice);

                // 成人单票价格 + 服务费
                BigDecimal adultChargePrice = seatLevelCacheDTO.getPcPrice().add(seatLevelCacheDTO.getServiceChargePrice());

                // 小童单票价格 + 服务费
                BigDecimal childChargePrice = seatLevelCacheDTO.getPcChildPrice().add(seatLevelCacheDTO.getServiceChargePrice());

                BigDecimal price = adultChargePrice.multiply(BigDecimal.valueOf(req.getAdultNum())).
                        add(childChargePrice.multiply(BigDecimal.valueOf(req.getChildNum())));

                // 价格为总价
                detailPcDTO.setPrice(price);

                // 获取预订设置
                TrainProductReservationSettings settings = reservationSettingsMapper.selectById(MtrTrainSettingCode.ALI.getCode());
                if (settings != null) {
                    seatLevelCacheDTO.setChildrenNotice(settings.getChildrenNotice());
                    seatLevelCacheDTO.setPassengerNotice(settings.getPassengerNotice());
                    seatLevelCacheDTO.setBookingInformation(settings.getBookingInformation());
                }
            } else if (seatLevelCacheDTO.getIsAliProduct() == 0) {
                // 成人单票价格 + 服务费
                BigDecimal adultChargePrice = null;

                // 小童单票价格 + 服务费
                BigDecimal childChargePrice = null;
                if (Objects.equals(seatLevelCacheDTO.getServiceChargeType(), ServiceChargeType.PERCENTAGE.getCode())) {
                    BigDecimal percentage = seatLevelCacheDTO.getServiceChargePrice().divide(new BigDecimal("100"));
                    adultChargePrice = seatLevelCacheDTO.getPcPrice().multiply(percentage);
                    childChargePrice = seatLevelCacheDTO.getPcChildPrice().multiply(percentage);
                } else if (Objects.equals(seatLevelCacheDTO.getServiceChargeType(), ServiceChargeType.FIXED.getCode())) {
                    adultChargePrice = seatLevelCacheDTO.getPcPrice().add(seatLevelCacheDTO.getServiceChargePrice());
                    childChargePrice = seatLevelCacheDTO.getPcChildPrice().add(seatLevelCacheDTO.getServiceChargePrice());
                } else {
                    throw new BusinessException(SystemError.TRAIN_PRODUCT_14035);
                }
                BigDecimal price = adultChargePrice.multiply(BigDecimal.valueOf(req.getAdultNum()))
                        .add(childChargePrice.multiply(BigDecimal.valueOf(req.getChildNum())));

                // 价格为总价
                detailPcDTO.setPrice(price);
            }
        }
        return Result.success(detailPcDTO);
    }

    private BigDecimal getServiceChargeAmount(Long code, BigDecimal price, BigDecimal rate) {
        BigDecimal amount = new BigDecimal(0);
        if (code.equals(MainDataManualSystemCode.MANUAL_2.getCode())) {
            // 小于等于
            if (price.compareTo(new BigDecimal(100)) < 1) {
                amount = new BigDecimal(40);
                // 大于等于 && 小于等于
            } else if (price.compareTo(new BigDecimal(101)) > -1 && price.compareTo(new BigDecimal(400)) < 1) {
                amount = new BigDecimal(80);
                // 大于等于
            } else if (price.compareTo(new BigDecimal(401)) > -1) {
                amount = new BigDecimal(90);
            }
        } else {
            // 小于等于
            if (price.compareTo(new BigDecimal("199.5")) < 1) {
                amount = new BigDecimal(20);
                // 大于等于 && 小于等于
            } else if (price.compareTo(new BigDecimal(200)) > -1 && price.compareTo(new BigDecimal("299.5")) < 1) {
                amount = new BigDecimal(40);
                // 大于等于
            } else if (price.compareTo(new BigDecimal(300)) > -1) {
                amount = new BigDecimal(50);
            }
        }
        return amount;
    }

    /**
     * 根据币种ID获取汇率，获取汇率,
     *
     * @return
     */
    private MainDataCurrencyQueryDTO getExchangeRateByCurrencyId(Long currencyId) {
        MainDataCurrencyUpdateStatusReq mainDataCurrencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
        mainDataCurrencyUpdateStatusReq.setId(currencyId);
        Result<MainDataCurrencyQueryDTO> queryCurrencyRateResult = mainDataCurrencyService.query(mainDataCurrencyUpdateStatusReq);
        if (!queryCurrencyRateResult.isSuccess()) {
            SystemError defined = SystemError.getDefined(queryCurrencyRateResult.getCode());
            throw new BusinessException(defined);
        }
        return queryCurrencyRateResult.getData();
    }

    /**
     * 执行 K:V 缓存删除
     *
     * @param keys 需要删除的keys
     * @return
     */
    private Map<String, Boolean> deletString(List<String> keys) {
        Map<String, Boolean> map = new HashMap<>();
        keys.forEach(key -> {
            Boolean delete = redisTemplate.delete(key);
            map.put(key, delete);
        });
        return map;
    }
}
